using OrchardCore.ContentManagement;
using OrchardCore.Taxonomies.Models;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Lombiq.HelpfulLibraries.OrchardCore.Contents;

public class TaxonomyHelper : ITaxonomyHelper
{
    private readonly IContentHandleManager _contentHandleManager;
    private readonly IContentManager _contentManager;

    public TaxonomyHelper(IContentHandleManager contentHandleManager, IContentManager contentManager)
    {
        _contentHandleManager = contentHandleManager;
        _contentManager = contentManager;
    }

    public async Task<ContentItem> GetTermContentItemByTaxonomyAliasAsync(string alias, string termId) =>
        (await GetTermsOfTaxonomyByAliasAsync(alias, [termId])).FirstOrDefault();

    public async Task<IEnumerable<ContentItem>> GetTermsOfTaxonomyByIdAsync(string taxonomyId, IEnumerable<string> termIds)
    {
        if (string.IsNullOrWhiteSpace(taxonomyId) ||
            await _contentManager.GetAsync(taxonomyId) is not { } contentItem)
        {
            return [];
        }

        var ids = termIds?.AsList();
        return ids is null
            ? GetAllChildren(contentItem)
            : GetSelected(contentItem, ids);
    }

    public async Task<IEnumerable<ContentItem>> GetTermsOfTaxonomyByAliasAsync(string taxonomyAlias, IEnumerable<string> termIds) =>
        await GetTermsOfTaxonomyByIdAsync(
            await _contentHandleManager.GetContentItemIdAsync($"alias:{taxonomyAlias}"),
            termIds);

    /// <summary>
    /// 返回分类树中的所有子内容项。
    /// </summary>
    /// <param name="contentItem">要枚举的树的根。</param>
    /// <param name="includeSelf">
    /// 如果为 <see langword="true"/>，则 <paramref name="contentItem"/> 将是第一个结果，因此只要 <paramref name="contentItem"/> 不为 <see langword="null"/>，集合就永远不会为空。
    /// </param>
    /// <returns>所有子项的无序列表。</returns>
    public static IList<ContentItem> GetAllChildren(ContentItem contentItem, bool includeSelf = false)
    {
        var results = new List<ContentItem>();
        if (contentItem == null) return results;
        if (includeSelf) results.Add(contentItem);

        var partTerms = contentItem.As<TaxonomyPart>()?.Terms ?? Enumerable.Empty<ContentItem>();
        var itemTerms = contentItem.GetProperty<List<ContentItem>>(nameof(TaxonomyPart.Terms)) ?? Enumerable.Empty<ContentItem>();
        foreach (var child in partTerms.Concat(itemTerms))
        {
            results.AddRange(GetAllChildren(child, includeSelf: true));
        }

        return results;
    }

    /// <summary>
    /// 返回分类树中 ID 在 <paramref name="selectedIds"/> 中列出的子内容项。
    /// </summary>
    public static IEnumerable<ContentItem> GetSelected(ContentItem contentItem, ICollection<string> selectedIds) =>
        GetAllChildren(contentItem)
            .Where(term => selectedIds.Contains(term.ContentItemId));
}
